package coherence;
import java.util.List;
import multiarray.MultiArray;



public class CrossSectionToCoalition implements CrossSectionToCoalitionInterface{

	private MultiArray<MultiArray<Float>> altruisms;
	private MultiArray<Float> populationByCrossSection;	
	private MultiArray<Float> powerByCrossSection;
	private List<List<int []>> partition;
	
	private float[][][][] betas;
	private int numCoalitions;
	private float[] sigma_i;
	private int[] coalitionSizes;
	private float[][] averagedBetas;
	
	public static CrossSectionToCoalitionInterface getNewCrossSectionToCoalition(MultiArray<MultiArray<Float>> altruisms,
			List<List<int[]>> partition,
			MultiArray<Float> populationByCrossSection,
			MultiArray<Float> powerByCrossSection){
		return new CrossSectionToCoalition(altruisms,
				partition,
				populationByCrossSection,
				powerByCrossSection);
	}
	
	public CrossSectionToCoalition(MultiArray<MultiArray<Float>> altruisms,
			List<List<int[]>> partition,
			MultiArray<Float> populationByCrossSection,
			MultiArray<Float> powerByCrossSection) {
		super();
		this.altruisms = altruisms;
		this.partition = partition;
		this.populationByCrossSection = populationByCrossSection;
		this.powerByCrossSection = powerByCrossSection;
		
		numCoalitions = partition.size();
		computeCoalitionSizes();
		computeBetas();
		computeSigmas();
		
	}	
	
	private void computeSigmas(){
		numCoalitions = partition.size();
		float[] sigma_i = new float[numCoalitions];
		for(int i = 0; i < numCoalitions; i++){
			List<int []> coalition = partition.get(i);
			for(int [] crossSection : coalition){
				sigma_i[i] += populationByCrossSection.getElementAtIndex(crossSection);
			}
		}
	}	
	
	private void computeCoalitionSizes(){
		coalitionSizes = new int[numCoalitions];
		for(int i = 0; i < numCoalitions; i++){
			coalitionSizes[i] = partition.get(i).size();
		}
	}	
	
	private void computeBetas(){
		
		betas = new float[numCoalitions][numCoalitions][][];
		averagedBetas = new float[numCoalitions][numCoalitions];
		
		for(int i = 0; i < numCoalitions; i++){
			List<int []> coalition_i = partition.get(i);
			for(int j = 0; j < numCoalitions; j++){
				List<int []> coalition_j = partition.get(j);
				
				float[][] result = new float[coalitionSizes[i]][coalitionSizes[j]];
				
				float sourceTotalPopulation = 0;
				float sourceTotalAltruism = 0;
				
				float[] targetAveragedAltruisms = new float[coalitionSizes[i]];
				
				for(int m = 0; m < coalitionSizes[i]; m++){
					float targetTotalAltruism = 0;
					float targetTotalPopulation = 0;
					for(int n = 0; n < coalitionSizes[j]; n++){
						result[m][n] = altruisms.
						getElementAtIndex(coalition_i.get(m)).
						getElementAtIndex(coalition_j.get(n));
						float targetPopulation = populationByCrossSection.
						getElementAtIndex(coalition_j.get(n));
						targetTotalAltruism += result[m][n] * targetPopulation;
						targetTotalPopulation += targetPopulation;
					}
					
					targetAveragedAltruisms[m] = targetTotalAltruism/targetTotalPopulation;
					float sourcePopulation = populationByCrossSection.
					getElementAtIndex(coalition_i.get(m));
					sourceTotalAltruism += targetAveragedAltruisms[m] * sourcePopulation;
					sourceTotalPopulation += sourcePopulation;
				}		
				betas[i][j] = result;
				averagedBetas[i][j] = sourceTotalAltruism/sourceTotalPopulation;
			}
		}
	}
	
	@Override
	public float[][] getCoalitionalBetas(){
		return averagedBetas;
	}
	
	@Override
	public float[] getSigmas(){
		return sigma_i;
	}	
	
}
